<?php
/* This file is part of the UARX PHP5 library <http://www.uarx.net/php5lib>.
 * Copyright (C) 2011 UARX Networks.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/** 
 * @file   fileCacheEngine.php
 * @brief  UARX PHP5 library file that contains a class definition for a File
 *         Cache Engine.
 * @date   Mar 28, 2011
 * @author Andres Villa <avilla@uarx.com>
 */

/**
 * @class fileCacheEngine
 * @brief Implements a file based cache using PHP.
 */
class fileCacheEngine
{
/*! @publicsection */

	/**
	 * Constructor of File Cache Engine.
	 *
	 * @param appId     Application ID used to identify cached files into the
	 *                  filesystem.
	 */
	public function __construct($appId = "uarxCache")
	{
		// Assign the class application identifier with the provided App ID.
		$this->p_appId = $appId;
	}

	/**
	 * Get a cache resource from the cache engine.
	 *
	 * @param uid       The unique identifier of the cache resource.
	 * @param timeout   The maximum time to consider cache valid. A zero value
	 *                  represents a cache that doesn't exipires.
	 * @return          The unserialized contents of the cache if exists and
	 *                  is valid, or false.
	 */
	public function get_cache($uid, $timeout = 0)
	{
		// Generate the path and filename to look for in the cache
		$cacheName = $this->generate_uid_filename($uid);
		// Verify if the file exists
		if(! file_exists($cacheName))
		{
			// File doesn't exist, we cannot proceed. Return false.
			return false;
		}
		else
		{
			// Ok, file exists. But is it still valid?
			if($timeout == 0)
			{
				// Time doesn't matters, so return what we have!
				return unserialize($this->read_cache($cacheName));
			}
			else
			{
				// Obtain the maximum valid time
				$timeLimit = time() - (int)$timeout;
				// Cache is only valid if timeout was not passed
				if(filemtime($cacheName) > $timeLimit)
				{
					// Good, file is still valid. Return what we have!
					return unserialize($this->read_cache($cacheName));
				}
				else
				{
					// Cache file is no longer valid. Proceed to delete it...
					$this->unset_cache($uid);
					// We don't have anything to return, just return false
					return false;
				}
			}
		}
	}

	/**
	 * Insert a cache resource into the filesystem with the given data.
	 *
	 * @param uid       A unique identifier of the cache resource.
	 * @param data      Data to be cached.
	 * @return          True in every case, but raises an error if cache can
	 *                  not be opened.
	 */
	public function set_cache($uid, $data)
	{
		// Call the serialize method to convert the information to be cached
		$data = serialize($data);
		// Generate the path and filename to use to store the cache
		$cacheName = $this->generate_uid_filename($uid);		
		// Open a temporary file to write
		if(!$file = fopen($cacheName . getmypid(), "wb"))
		{
			// Trigger error
			echo "Failed to open tmpfile for write<Br>";
		}
		// Write the information to the file
		fwrite($file, $data, strlen($data));
		// Close the file
		fclose($file);
		// Rename the temporary created file to the final name
		rename($cacheName . getmypid(), $cacheName);
		// Just return true if we could do all these...
		return true;
	}

	/**
	 * Delete a cache resource from the filesystem.
	 *
	 * @param uid       The unique identifier of the cache resource.
	 * @return          True if the cache resource is deleted, or false if not.
	 */
	public function unset_cache($uid)
	{
		// Generate the filename based on the given uid
		$cacheName = $this->generate_uid_filename($uid);
		// Lookup if the file exists
		if(file_exists($cacheName))
		{
			// Attempt to delete it
			if(! unlink($cacheName))
			{
				// TODO: Trigger an error with trigger_error
				echo get_class($this) . "::unset_cache Unable to delete file from cache.<br>";
				// We just failed, return false
				return false;
			}
			else
			{
				// The file was deleted. We need to clear PHP cache because
				// when using file_exists the result can be cached
				clearstatcache();
				// Now we have finished, return true
				return true;
			}
		}
		else
		{
			// File doestn't exist, return true
			return true;
		}
	}

/*! @protectedsection */

	/**
	 * Generates a Unique Identifier file path based on a given resource
	 * unique identifier.
	 *
	 * @param uid       A unique identifier name for the cache resource.
	 * @return          A string that contains the Unique Identifier filename
	 *                  and path.
	 */
	protected function generate_uid_filename($uid)
	{
		$retFilename = "cache/~" . $this->p_appId . "_" . $uid;
		return $retFilename;
	}
	
	/**
	 * Read the contents of a specific cache file and return it unserialized.
	 *
	 * @param filename  The cache filename and path to read from.
	 * @return          A unserialized mixed value with cache contents. The
	 *                  returned value can be a boolean, integer, float,
	 *                  string, array, or object.
	 */
	protected function read_cache($filename)
	{
		// Check for PHP version to be sure that set_magic_quotes_runtime is
		// not deprecated. It has been DEPRECATED as of PHP 5.3.0.
		if(version_compare(PHP_VERSION, '5.3.0') < 0)
		{
			// Obtain the actual settings for magic quotes
			$mqr_set = get_magic_quotes_runtime();
			// Switch magic quotes off
			set_magic_quotes_runtime(false);
		}
		// Attempt to read from the file
		if(! $data = file_get_contents($filename))
		{
			// TODO: Trigger an error
			echo get_class($this) . "::read_cache Error readin file contents<br>";
			$data = false;
		}
		// Check for PHP version to be sure that set_magic_quotes_runtime is
		// not deprecated. It has been DEPRECATED as of PHP 5.3.0.
		if(version_compare(PHP_VERSION, '5.3.0') < 0)
		{
			// Get back previous settings to its state
			set_magic_quotes_runtime($mqr_set);
		}
		// Return what we have in our cache
		return $data;		
	}

	/* Parameters */
	protected $p_appId;
}
?>